#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "dtk_types.h"
#include "dtk_vsgroup.h"

DTKVisualStateGroup* dtk_vsg_create (DInt id)
{
    DTKVisualStateGroup* vsg;

    vsg = (DTKVisualStateGroup*) malloc (sizeof(DTKVisualStateGroup));
    memset (vsg, 0, sizeof(DTKVisualStateGroup));

    vsg->id = id;
    dtk_list_init(DLIST(vsg), (DPointer)vsg);
    dtk_link_init(DLINK(vsg), (DPointer)vsg);

    return vsg;
}

static DBoolean free_vs (DList* list, DLink* link, va_list args)
{
    DTKVisualState* sub;

    sub = (DTKVisualState*)DLINKDATA(link);

    dtk_list_remove(list, link);
    dtk_vs_free(sub);
    return DTK_FALSE;
}

void dtk_vsg_free(DTKVisualStateGroup* self)
{
    if (self == NULL)
    {
        return;
    }

    dtk_list_foreach(DLIST(self), free_vs);
    
    free (self);
    return;
}

void dtk_vsg_remove(DTKVisualStateGroup* self, DTKVisualState* vs)
{
    
    if (self == NULL || vs == NULL)
    {
        return;
    }

    dtk_list_remove(DLIST(self), DLINK(vs));

    return;
}

static DBoolean add_vs(DList* list, DLink* link, va_list args)
{
    DTKVisualState* new_vs;
    DTKVisualState* vs = (DTKVisualState*)DLINKDATA(link);

    new_vs = va_arg(args, DTKVisualState*);

    if (vs->state == new_vs->state)
    {
        dtk_list_remove(list, link);
        dtk_vs_free(vs);
        return DTK_TRUE;
    }
    return DTK_FALSE;
}

void dtk_vsg_add(DTKVisualStateGroup* self, DTKVisualState* vs, DBoolean is_default)
{
    DInt count;
    
    if (self == NULL || vs == NULL)
    {
        return;
    }

    if (dtk_list_contains_element (DLIST(self), DLINK(vs)))
    {
        return;
    }

    count = dtk_list_get_count(DLIST(self));
    dtk_list_foreach (DLIST(self), add_vs, vs);
    dtk_list_append (DLIST(self), DLINK(vs));

    if (count == 0 || is_default == DTK_TRUE)
    {
        self->current_state = vs->state;
        dtk_vs_active(vs);
    }
    
    return;
}

static DBoolean get_state(DList* list, DLink* link, va_list args)
{
    DInt state;
    DTKVisualState** ret_vs;
    DTKVisualState* vs = (DTKVisualState*)DLINKDATA(link);

    state = va_arg(args, DInt);
    ret_vs = va_arg(args, DTKVisualState**);

    if (vs->state == state)
    {
        *ret_vs = vs;
        return DTK_TRUE;
    }
    return DTK_FALSE;
}

DTKVisualState* dtk_vsg_get_state (DTKVisualStateGroup* self, DInt state)
{
    DTKVisualState* vs = NULL;

    if (self == NULL)
    {
        return NULL;
    }

    dtk_list_foreach (DLIST(self), get_state, state, &vs);

    return vs;
}

DBoolean dtk_vsg_goto_state (DTKVisualStateGroup* self, DInt state)
{
    DTKVisualState* vs = NULL;

    if (self->current_state == state)
    {
        return DTK_TRUE;
    }

    vs = dtk_vsg_get_state(self, state);
    if (vs == NULL)
    {
        return DTK_FALSE;
    }

    self->current_state = state;

    dtk_vs_active(vs);

    return DTK_TRUE;
}